package com.arpa.ntocc.common.security;

import com.arpa.ntocc.common.security.filter.OauthAuthorizeFilter;
import com.arpa.ntocc.common.security.filter.OauthLogoutFilter;
import com.arpa.ntocc.common.security.filter.PartyFilter;
import com.arpa.ntocc.common.security.realm.StatelessAuthorizingRealm;
import com.arpa.ntocc.common.service.authorize.AuthorizeTokenService;
import com.google.common.collect.Maps;
import org.apache.shiro.mgt.DefaultSessionStorageEvaluator;
import org.apache.shiro.mgt.DefaultSubjectDAO;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.mgt.DefaultWebSubjectFactory;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.servlet.Filter;
import java.util.Map;

/**
 * Rest 无状态Shiro 配置
 *
 * @author leo
 */
@Configuration
public class ShiroConfiguration {


    @Autowired
    private AuthorizeTokenService authorizeTokenService;

    private static final Map<String, String> filterChainDefinitionMap = Maps.newLinkedHashMap();
    private static final Map<String, Filter> filters = Maps.newLinkedHashMap();

    @Bean
    public StatelessAuthorizingRealm statelessAuthorizingRealm() {
        StatelessAuthorizingRealm realm = new StatelessAuthorizingRealm();
        return realm;
    }
    /**
     * 权限管理器
     *
     * @return
     */
    @Bean
    public DefaultWebSecurityManager securityManager() {
        DefaultWebSecurityManager dwsm = new DefaultWebSecurityManager();
        dwsm.setRealm(statelessAuthorizingRealm());
        // 配置subject工厂
        dwsm.setSessionManager(sessionManager());
        // 禁用使用Sessions 作为存储策略的实现，但它没有完全地禁用Sessions,所以需要配合context.setSessionCreationEnabled(false);
        ((DefaultSessionStorageEvaluator) ((DefaultSubjectDAO) dwsm.getSubjectDAO()).getSessionStorageEvaluator()).setSessionStorageEnabled(false);

        return dwsm;
    }

    @Bean
    public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager());
        filters.put("logout", getLogoutFilter());
        filters.put("oauth", getOauthAuthorizeFilter());
        filters.put("party", getPartyFilter());
        shiroFilterFactoryBean.setFilters(filters);
        filterChainDefinitionMap.put("/logout", "logout");
        //放弃shiro权限过滤，改用@NeedLogin,@NeedRole,@NeedPermission注解
        filterChainDefinitionMap.put("/**", "anon");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return shiroFilterFactoryBean;
    }

    /**
     * 使用自定义的已关闭session的 subject工厂管理器
     *
     * @return
     */
    @Bean
    public DefaultWebSubjectFactory subjectFactory() {
        StatelessDefaultSubjectFactory subjectFactory = new StatelessDefaultSubjectFactory();
        return subjectFactory;
    }

    /**
     * session管理器：
     * sessionManager通过sessionValidationSchedulerEnabled禁用掉会话调度器，
     * 因为我们禁用掉了会话，所以没必要再定期过期会话了。
     *
     * @return
     */
    @Bean
    public SessionManager sessionManager() {
//        DefaultSessionManager sessionManager = new DefaultSessionManager();
        DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
        sessionManager.setSessionValidationSchedulerEnabled(false);
        return sessionManager;
    }

    /**
     * Add.5.1
     * 开启shiro aop注解支持.
     * 使用代理方式;所以需要开启代码支持;
     *
     * @param securityManager
     * @return
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }

    /**
     * Add.5.2
     * 自动代理所有的advisor:
     * 由Advisor决定对哪些类的方法进行AOP代理。
     */
    @Bean
    public DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator daap = new DefaultAdvisorAutoProxyCreator();
        daap.setProxyTargetClass(true);
        return daap;
    }

    private OauthAuthorizeFilter getOauthAuthorizeFilter() {
        OauthAuthorizeFilter oauthAuthorizeFilter = new OauthAuthorizeFilter();
        oauthAuthorizeFilter.setAuthorizeTokenService(authorizeTokenService);
        return oauthAuthorizeFilter;
    }

    private OauthLogoutFilter getLogoutFilter() {
        OauthLogoutFilter oauthLogoutFilter = new OauthLogoutFilter();
        oauthLogoutFilter.setAuthorizeTokenService(authorizeTokenService);
        return oauthLogoutFilter;
    }

    private PartyFilter getPartyFilter() {
        PartyFilter partyFilter = new PartyFilter();
        return partyFilter;
    }

}
